#!/usr/bin/python3
# -*- coding:utf-8 -*-
""""
@Author: lijk34925
@Time: 2024/3/7 9:49
@File: common_test_prepare.py
"""
import os
import re
import traceback

from qturboframe.lib.utils.variable import Variable
from qturboframe.lib.webdriver import SeleniumError

from AmlScripts.amlConfig import amlConfig
from BladeFerm.Lib.Common import logger
from BladeFerm.databases.DealSql.EnvConfig import EnvConfig
from BladeFerm.databases.DealSql.Unisql import Unisql
from BladeFerm.hui2_app.basic import sys_login
from BladeFerm.utils.FileOerate import getFilePath
from BladeFerm.databases import DB_APP

BladeVariable = Variable()


def get_blade_param(name="", default=""):
    """
    获取blade平台的参数
    :param name:
    :param default:
    :return:
    """
    result = BladeVariable.get_variable(name)
    if result and result != 'AGENT_EMPTY':
        result_last = result
    else:
        result_last = default
    logger.info(f"get_blade_param: {name} = {result_last}")
    return result_last


def check_result(result: dict, check_servers=None):
    """
    断言服务启动结果
    :param result: 检查结果
    :param check_servers: 要检查的服务名称，为空时默认检查所有服务！
    :return:
    """
    if not check_servers:
        check_servers = ",".join(list(result.keys()))
    for key, value in result.items():
        if not value and re.search(key, check_servers, re.I):
            error = f"{key} 服务重启失败！不适宜继续后续测试流程"
            logger.error(error)
            raise SeleniumError(error)


def test_db_link(func):
    """
    装饰器：测试数据库连接
    :param func:
    :return:
    """
    def wrapper(*args, **kwargs):
        BV = Variable()
        system_env = BV.get_variable('varg_db_type')
        init_env = amlConfig.get('env')
        system_env_real = system_env if system_env != 'AGENT_EMPTY' and system_env else init_env
        try:
            if re.search("pg", system_env_real, re.I):
                sql_status = "select 1"
            else:
                sql_status = "select 1 from dual"
            DB_APP.run_one_sql(sql_status)
            # 执行脚本
            func(*args, **kwargs)
        except SystemExit as e:
            logger.info(f"脚本被终止调用成功！TIP:{e}")
        except Exception as e:
            error_info = traceback.format_exc()
            pattern = f"java.sql.SQLNonTransientConnectionException|connection closed"
            if re.search(pattern, str(error_info), re.I):
                logger.warning(f"数据库连接异常，重新连接数据库")
                system_odbc_config = amlConfig.get(system_env_real).get('databases')
                system_odbc_config.update({'env': system_env_real})
                logger.info(f'Init db link! system_odbc_config: {system_odbc_config}')
                DB_APP.make_db(**system_odbc_config)
            else:
                logger.error(f"format_exc: {error_info}")
                raise SeleniumError(f"UI test error: {e}")
        finally:
            logger.info("数据库连接检查完成：！")
    return wrapper


# 执行sql脚本写入
@test_db_link
def sql_handle_class(env, path):
    act_sql_list = []
    if path and os.path.isfile(path):
        fp, fn = os.path.split(path)
        fn_name, ext = os.path.splitext(fn)
        v_fn_name = "varg_sql_filename"
        sql_act_filename = BladeVariable.get_variable(v_fn_name)
        if sql_act_filename and sql_act_filename == fn_name:
            logger.info(f"已经运行过sql文件：{path}")
        else:
            BladeVariable.set_variable(v_fn_name, fn_name)
            # blade_exec_sql(path=path, env=env)  # 运行sql文件插入
            # sql_list = read_sql_file(filename=path)
            sql_list = Unisql(path=path, env=env, config=amlConfig)
            act_results = DB_APP.get_run_sql_result(sql_list)
            logger.info(f"执行sql文件：{path} 完成！")
            act_sql_list = sql_list
            # 检查sql执行结果 若存在失败则Fail
            act_sql_result_flag = True
            for index, result in act_results.items():
                if len(result) > 0 and result[0].get('ERROR_CODE', None):
                    err_info = result[0].get('ERROR_INFO', '')
                    logger.error(err_info)
                    act_sql_result_flag = False
            if not act_sql_result_flag:
                raise SeleniumError("SQL执行存在失败，请检查！")
            else:
                logger.info("SQL脚本执行全部Pass！")
    else:
        logger.error(f"sql文件：{path} 不存在，请检查！")
    return act_sql_list


def login_web_page():
    """
    登录web页面：从blade的环境配置获取地址信息
    :return:
    """
    varb = Variable()
    env = varb.get_variable('varg_db_type')
    current_path = ""
    if env and env != 'AGENT_EMPTY':
        current_path = varb.get_variable('varu_CurrentPath')
        res = re.search(r"data\\(.*?)\\(.*?)\\标准数据", current_path)
        project_name = res.group(1) if res else ""
        ENV = EnvConfig(env, config=amlConfig)
        url = ENV.url
        user = ENV.user
        pwd = ENV.pwd
        logger.info(f"blade环境信息：{env}, 项目名称: {project_name}, url: {url}, user: {user}, pwd: {pwd}")
        # 记录执行次数，超过一定次数后，以清除页面的缓存，防止长时间运行用例导致浏览器崩溃
        run_count = varb.get_variable('varg_run_count')
        logger.debug(f"varg_run_count: {run_count}")
        if run_count == 'AGENT_EMPTY' or not run_count:
            sys_login(user, pwd, url)
            varb.set_variable('varg_run_count', '0')
        elif run_count and int(run_count) > 50:
            sys_login(user, pwd, url)
            varb.set_variable('varg_run_count', '0')
        else:
            varb.set_variable('varg_run_count', str(int(run_count) + 1))
    return env, current_path


# 装饰器，处理入参，sql写入，浏览器登录操作等
def common_test_prepare(func):
    def test_data_prepare(input_data_raw, env, current_path):
        # 检查是否需要执行sql脚本
        if "任务编号" in list(input_data_raw.keys()) or "规则编号" in list(input_data_raw.keys()):
            task_name = input_data_raw.get('任务编号')
            project_web_path = os.path.join(current_path, "数据预埋\\指标规则")
            rule_no = input_data_raw.get('规则编号', None)
            if rule_no:  # 可疑规则取规则编号
                rule_version = input_data_raw.get('规则版本', '1000')
                task_name = rule_no + '_' + rule_version
                project_web_path = os.path.join(current_path, "数据预埋\\指标规则\\可疑规则")
            sql_path = getFilePath(str(task_name) + '.*\.sql', project_web_path)
            sql_list = sql_handle_class(env, sql_path)
            return sql_list
        else:
            project_web_path = os.path.join(current_path, "数据预埋\\基础功能")
            case_sql_name = input_data_raw.pop('SQL脚本', '')
            if case_sql_name:
                sql_path = getFilePath(case_sql_name, project_web_path)
                logger.info(f'sql_script_path:{sql_path}')
                sql_list = sql_handle_class(env, sql_path)
                return sql_list
            else:
                return []

    # 测试公共准备工作，数据读取，UI登录
    def wrapper(*args, **kwargs):
        logger.debug(f"wrapper:{args} {kwargs}")
        if args:
            input_data = args[0]
            ui_expect = args[1]
        else:
            input_data = kwargs.get('input_data')
            ui_expect = kwargs.get('ui_expect')
        if ui_expect.get('result', None) is not None:
            ui_expect.pop('result', None)
        logger.info(f'入参：{input_data}')
        logger.info(f'期望：{ui_expect}')
        delete_sql_list = list()
        try:
            env, current_path = login_web_page()
            if current_path:
                # 测试数据准备
                sql_list = test_data_prepare(input_data, env, current_path)
                delete_sql_list = [re.match(r"delete ", sql, re.I | re.M) for sql in sql_list]
            # 执行脚本
            func(*args, **kwargs)
        except SystemExit as e:
            logger.info(f"脚本被终止调用成功！TIP:{e}")
        except Exception as e:
            logger.error(f"error: {e}")
            error_info = traceback.format_exc()
            logger.error(f"format_exc: {error_info}")
            raise SeleniumError(f"UI test error: {e}")
        finally:
            if delete_sql_list:
                logger.info(f"执行删除sql脚本:{delete_sql_list}")
                DB_APP.get_run_sql_result(delete_sql_list)
            logger.info("脚本执行完成！")
    return wrapper


def catch_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            func(*args, **kwargs)
        except SystemExit as e:
            logger.info(f"脚本被终止调用成功！TIP:{e}")
        except Exception as e:
            logger.error(f"error: {e}")
            error_info = traceback.format_exc()
            logger.error(f"format_exc: {error_info}")
            raise SeleniumError(f"UI test error: {e}")
        finally:
            logger.info("脚本执行完成！")
    return wrapper


# 装饰器用法示例
def demo_test_prepare(input_data=None, ui_expect=None):
    logger.info("测试装饰器成功！")


if __name__ == '__main__':
    input_data = {'is_blade_platform': False}
    demo_test_prepare(input_data=input_data, ui_expect=None)